package org.springframework.extcache;

import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.springframework.cache.CacheManager;

public abstract class AbstractConfiggurableCache implements ConfigurableCache {
  protected KeyValueParser keyValueParser;        // 自定义参数解析器
  protected boolean        isInitialized = false; // 是否初始化
  protected String         actualKey;             // 缓存的key
  private String           originalKey;           // 原始的，未修改过的key
  protected int            expireTimeOfManager;   // manager的expireTime
  protected Object         value;
  protected String         version;
  private CacheManager     cacheManager;
  protected String         name;

  @Override
  public int getExpireTime() {
    String value = keyValueParser.get(EXPIRETIME_KEY);
    if (value != null) {
      return Integer.parseInt(value);
    }
    if (expireTimeOfManager > 0) {
      return expireTimeOfManager;
    }
    return 0;
  }

  public String getName() {
    return name;
  }

  @Override
  public String getParams() {
    if (isInitialized) {
      return keyValueParser.get(METHOD_PARAMS_KEY);
    }
    return null;
  }

  @Override
  public String getActualKey() {
    return actualKey;
  }

  public void setActualKey(String actualKey) {
    this.actualKey = actualKey;
  }

  /**
   * 键值对解析器<br>
   * 例如：userCache155589911,EXPIRTTIME=10 -> {"EXPIRETIME":"10"}
   * 
   * @author zhangz8@yeah.net
   * @date 2019年9月30日下午5:32:06
   */
  public class KeyValueParser {
    private Map<String, String> data;

    private KeyValueParser(String input) {
      this.data = getData(input);
    }

    public String get(String key) {
      return data.get(key.toUpperCase());
    }

    public void put(String key, String value) {
      this.data.put(key.toUpperCase(), value);
    }

    private Map<String, String> getData(String input) {
      Map<String, String> data = new HashMap<String, String>(5);
      this.data = data;

      MethodParamHandler methodParamHandler = new MethodParamHandler();
      String[] methodParamKeyValue = methodParamHandler.handle(input);
      if (methodParamKeyValue != null) {
        put(methodParamKeyValue[0], methodParamKeyValue[1]);
      }

      ExpireTimeHandler expireTimeHandler = new ExpireTimeHandler();
      String[] expireTimeKeyValue = expireTimeHandler.handle(input);
      if (expireTimeKeyValue != null) {
        put(expireTimeKeyValue[0], expireTimeKeyValue[1]);
      }
      return data;
    }
  }

  class MethodParamHandler implements KeyValueHandler {
    final String obj2StringReg     = "\\s*,?\\s*" + METHOD_PARAMS_KEY + "\\s*=\\s*\\w+\\s*\\[([^\\]\\[])*\\]";// 对象标准toString的规则
    final String noneObj2StringReg = "\\s*,?\\s*" + METHOD_PARAMS_KEY + "\\s*=\\s*\\w+\\s*,?";                // 非对象的规则

    @Override
    public String[] handle(String rawKey) {
      if (rawKey.indexOf(METHOD_PARAMS_KEY) > -1) {
        String[] keyValue = new String[2];
        keyValue[0] = METHOD_PARAMS_KEY;
        Matcher matcher = Pattern.compile(obj2StringReg, Pattern.CASE_INSENSITIVE).matcher(rawKey);
        if (matcher.find()) {
          String value = matcher.group();
          value = replaceSpace(value);
          keyValue[1] = value;
          return keyValue;
        } else {
          matcher = Pattern.compile(noneObj2StringReg, Pattern.CASE_INSENSITIVE).matcher(rawKey);
          if (matcher.find()) {
            String value = matcher.group();
            value = replaceSpace(value);
            keyValue[1] = value;
            return keyValue;
          }
        }
      }
      return null;
    }

    @Override
    public String clean(String rawKey) {
      if (handle(rawKey) != null) {
        String clear = new String(rawKey);
        Matcher matcher = Pattern.compile(obj2StringReg, Pattern.CASE_INSENSITIVE).matcher(rawKey);
        if (matcher.find()) {
          return clear.replaceAll(obj2StringReg, "");
        } else {
          matcher = Pattern.compile(noneObj2StringReg, Pattern.CASE_INSENSITIVE).matcher(rawKey);
          if (matcher.find()) {
            return clear.replaceAll(noneObj2StringReg, "");
          }
        }
      }
      return rawKey;
    }
  }

  class ExpireTimeHandler implements KeyValueHandler {
    final String expireTimeReg = "\\s*,?\\s*" + EXPIRETIME_KEY + "\\s*=\\s*\\w+\\s*,?";

    @Override
    public String[] handle(String rawKey) {
      if (rawKey.indexOf(EXPIRETIME_KEY) > -1) {
        String[] keyValue = new String[2];
        keyValue[0] = EXPIRETIME_KEY;
        Matcher matcher = Pattern.compile(expireTimeReg, Pattern.CASE_INSENSITIVE).matcher(rawKey);
        if (matcher.find()) {
          String value = matcher.group();
          value = value.replaceAll("\\s*" + EXPIRETIME_KEY + "\\s*=\\s*", "");
          value = replaceSpace(value);
          keyValue[1] = value;
          return keyValue;
        }
      }
      return null;
    }

    @Override
    public String clean(String rawKey) {
      if (handle(rawKey) != null) {
        String clear = new String(rawKey);
        return clear.replaceAll(expireTimeReg, "");
      }
      return rawKey;
    }

  }

  protected String replaceSpace(String value) {
    value = value.replaceAll("\\s*,?\\s*" + METHOD_PARAMS_KEY + "\\s*=\\s*", "");
    value = value.replaceAll(REPLACE_HEAD_REG, "");
    value = value.replaceAll(REPLACE_TAIL_REG, "");
    return value;
  }

  public interface KeyValueHandler {

    /**
     * 处理字符串中的keyValue
     * 
     * @param rawKey
     * @return
     */
    String[] handle(String rawKey);

    /**
     * 清除字符串中的keyValue参数
     * 
     * @param rawKey
     * @return
     */
    String clean(String rawKey);
  }

  protected boolean init(Object objKey) {
    String rawKey = objKey.toString();
    if (!isInitialized) {
      String key = new String(rawKey);
      setOriginalKey(rawKey);
      MethodParamHandler methodParamHandler = new MethodParamHandler();
      key = methodParamHandler.clean(key);

      ExpireTimeHandler expireTimeHandler = new ExpireTimeHandler();
      key = expireTimeHandler.clean(key);
      key = key.replaceAll(REPLACE_TAIL_REG, "");
      keyValueParser = new KeyValueParser(rawKey);
      this.actualKey = getName() + key;

      isInitialized = true;
    }
    return isInitialized;
  }

  public boolean isInitialized() {
    return isInitialized;
  }

  public Object getValue() {
    return value;
  }

  public CacheManager getCacheManager() {
    return cacheManager;
  }

  public void setCacheManager(CacheManager cacheManager) {
    this.cacheManager = cacheManager;
  }

  @Override
  public void setIsInitialized(boolean isInitialized) {
    this.isInitialized = isInitialized;
  }

  public void setKeyValueParser(KeyValueParser keyValueParser) {
    this.keyValueParser = keyValueParser;
  }

  @Override
  public String getOriginalKey() {
    return originalKey;
  }

  @Override
  public void setOriginalKey(String originalKey) {
    this.originalKey = originalKey;
  }

}
